﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Data;

namespace ibba.src.sl.recursos
{
    public enum eTypeDetail
    {
        None, Insert, Update, Delete
    }

    public interface IDetailAux
    {
        eTypeDetail TypeDetail { get; set; }
    }

    /// <summary>
    /// Classe auxiliar para popular e manipular uma lista de registros
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// 
    public class DetailsAux<T> : INotifyPropertyChanged where T : IDetailAux
    {
        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void RaisePropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;

            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));

        }

        #endregion

        public delegate void EventLoadDetails();
        public event EventLoadDetails OnLoadDetails;

        public delegate void EventChangeDetails();
        public event EventChangeDetails OnChangeDetails;

        public delegate void EventChangeDetailSelected();
        public event EventChangeDetailSelected OnChangeDetailSelected;

        public delegate void EventChangeTypeDetail(object sender, eTypeDetail oldType, eTypeDetail newType);
        public event EventChangeTypeDetail OnChangeTypeDetail;

        public bool ShowItemExcluded { get; set; }
        public bool ShowConfirmationExclusion { get; set; }

        public DetailsAux()
        {
            ListOC = new ObservableCollection<T>();

            ShowItemExcluded = true;
            ShowConfirmationExclusion = true;
        }

        protected eTypeDetail GetTipoAcaoSQL(object pDetalhe)
        {
            return (eTypeDetail)pDetalhe.GetType().GetProperty("TypeDetail").GetValue(pDetalhe, null);
        }
        protected void SetTipoAcaoSQL(object pDetalhe, eTypeDetail pTipo)
        {
            var old = GetTipoAcaoSQL(pDetalhe);

            pDetalhe.GetType().GetProperty("TypeDetail").SetValue(pDetalhe, (int)pTipo, null);

            if (OnChangeTypeDetail != null)
                OnChangeTypeDetail(pDetalhe, old, pTipo);
        }

        public void CarregarDetalhes(List<T> pListaEntidade, bool pManterItens)
        {
            if (pManterItens == false)
                ListOC.Clear();

            //ListaOC.AddRange(pListaEntidade);

            foreach (var item in pListaEntidade)
                ListOC.Add(item);

            if (OnLoadDetails != null)
                OnLoadDetails();
        }

        public List<T> ChangeSets
        {
            get { return ListOC.Where(e => !GetTipoAcaoSQL(e).Equals(eTypeDetail.None)).ToList(); }
        }

        public ObservableCollection<T> ListOC { get; private set; }
        private T _DetalheSelecionado;
        public T DetalheSelecionado
        {
            get
            {
                return _DetalheSelecionado;
            }
            set
            {
                _DetalheSelecionado = value;
                RaisePropertyChanged("DetalheSelecionado");

                if (OnChangeDetailSelected != null)
                    OnChangeDetailSelected();
            }
        }

        private PagedCollectionView _colecao;
        public PagedCollectionView Colecao
        {
            get
            {
                if (_colecao == null)
                    _colecao = new PagedCollectionView(ListOC);

                return _colecao;
            }
            set
            {
                if (_colecao != value)
                {
                    _colecao = value;
                    this.RaisePropertyChanged("Colecao");
                }
            }
        }

        //public void EditarDetalhe()
        //{
        //    if (GetTipoAcaoSQL(DetalheSelecionado).Equals(Enums.TipoAcaoSQL.None))
        //    {
        //        SetTipoAcaoSQL(DetalheSelecionado, Enums.TipoAcaoSQL.Update);
        //    }            
        //}

        private MVVM.DelegateCommand _commandAdd;
        public MVVM.DelegateCommand CommandAdd
        {
            get
            {
                if (_commandAdd == null)
                    _commandAdd = new MVVM.DelegateCommand(() => AddDetail());

                //_commandAdd = new DelegateCommand(delegate
                //{
                //    ListaOC.Add(default(T));
                //});
                return _commandAdd;
            }
        }

        public void AddDetail()
        {
            AddDetail(Activator.CreateInstance<T>());
        }

        public void AddDetail(T pItem)
        {
            //if (pItem == null)
            //    pItem= Activator.CreateInstance<T>();

            SetTipoAcaoSQL(pItem, eTypeDetail.Insert);

            ListOC.Add(pItem);
            if (OnChangeDetails != null)
                OnChangeDetails();
        }

        private MVVM.DelegateCommand _commandRemove;
        public MVVM.DelegateCommand CommandRemove
        {
            get
            {
                if (_commandRemove == null)
                    _commandRemove = new MVVM.DelegateCommand(() => RemoveDetail());

                return _commandRemove;
            }
        }
        public virtual void RemoveDetail()
        {
            if (DetalheSelecionado == null)
            {
                MessageBox.Show("É necessário selecionar um registro.");
            }
            else
            {
                Deployment.Current.Dispatcher.BeginInvoke(() =>
                {
                    CheckRemove();
                });
            }
        }

        private MVVM.DelegateCommand _commandCheckRemove;
        public MVVM.DelegateCommand CommandCheckRemove
        {
            get
            {
                if (_commandCheckRemove == null)
                    _commandCheckRemove = new MVVM.DelegateCommand(() => CheckRemove());

                return _commandCheckRemove;
            }
        }
        public void CheckRemove()
        {
            eTypeDetail  acaoAtual = GetTipoAcaoSQL(DetalheSelecionado);

            //Se registro selecionado estiver sendo alterado ou já está gravado
            //então marca para exclusão
            if (acaoAtual == eTypeDetail.None || acaoAtual == eTypeDetail.Update || acaoAtual == eTypeDetail.Delete)
            {
                if (acaoAtual == eTypeDetail.Delete)
                    SetTipoAcaoSQL(DetalheSelecionado, eTypeDetail.Update);
                else
                    SetTipoAcaoSQL(DetalheSelecionado, eTypeDetail.Delete);

                //DetalheSelecionado = (T)pDetail; //no caso de atualizar deve força a seleção
                ApplyFilterCollection();
            }
            else
            {
                //Se for um registro novo apenas remove da lista
                ListOC.Remove(DetalheSelecionado);

            }

            if (OnChangeDetails != null)
                OnChangeDetails();

        }

        private void ApplyFilterCollection()
        {
            if (ShowItemExcluded)
            {
                if (Colecao.Filter != null)
                    Colecao.Filter = null;
            }
            else
            {
                Colecao.Filter = (f) => GetTipoAcaoSQL(f) != eTypeDetail.Delete;
            }

            Colecao.Refresh();
        }

        public void SaveDetails()
        {
            CarregarDetalhes((from o in ListOC where GetTipoAcaoSQL(o) != eTypeDetail.Delete select o).ToList(), false);

            foreach (T obj in ListOC)
            {
                SetTipoAcaoSQL(obj, eTypeDetail.None);
            }
        }

    }

}
